Dependency Injection(以下簡稱DI)相依性注入,是一種Design Pattern,DI帶來的好處多多,除了能減少耦合,增加元件的可用性,也可以讓單元測試更容易撰寫,這篇我們來學習如何在Blazor運用DI機制。
以下3個Service都是內建的,也就是說不用額外註冊或設定,只要在component中注入即可使用。
上述是Blazor內建的Service,如果要使用自訂的Service,也可以使用DI方式取得,那要怎麼用呢? 我們直接進入實例,這個例子很單純,在專案中加入一個MovieRepository,透過MovieRepository取的電影清單後顯示到頁面上。
public class MovieDTO
{
        public int Id { get; set; }
        public string Name { get; set; }
        public DateTime ReleaseDate { get; set; }
}
2.建立IMovieRepository,其中有一個GetMovies方法,再建立一個MovieRepository來實作IMovieRepository,這邊資料部分就不存取DB直接用模擬資料。
public interface IMovieRepository
{
    List<MovieDTO> GetMovies();
}
public class MovieRepository : IMovieRepository
    {
        public List<MovieDTO> AllMovie()
        {
            return new List<MovieDTO>()
            {
                new MovieDTO(){Id=1,Name="Batman : Gothom Knight",ReleaseDate=new DateTime(2020,8,1)},
                new MovieDTO(){Id=2,Name="Batman 2 : Two Face",ReleaseDate=new DateTime(2020,8,1)},
                new MovieDTO(){Id=3,Name="Batman 3 : Joker",ReleaseDate=new DateTime(2020,8,1)}
            };
        }
    }
接下來就要在DI註冊IMovieRepository了,在註冊時,我們有3種方式決定物件的生命週期
註冊物件的寫法上,有幾種方式。建議使用第一種,指定要使用的介面和實作類別,未來較方便抽換元件。
//指定介面和實作類別
services.AddSingleton<IMovieRepository, MovieRepository>();
//直接註冊new好的物件
MovieRepository movieRepository = new MovieRepository();
services.AddSingleton(movieRepository);
//指定介面和new好的物件
services.AddSingleton<IMovieRepository>(movieRepository);
最後在Blazor Server和Blazor WebAssembly的註冊方式有點不同。
Blazor Server--將註冊語法寫在StartUp.cs的ConfigureServices中
public void ConfigureServices(IServiceCollection services)
{
    services.AddRazorPages();
    services.AddServerSideBlazor();
            
    //註冊IMovieRepository
    services.AddSingleton<IMovieRepository, MovieRepository>();           
 }
Blazor WebAssembly — 將註冊語法寫在Program.cs的Main方法中
public static async Task Main(string[] args)
{
   var builder = WebAssemblyHostBuilder.CreateDefault(args);
   builder.RootComponents.Add<App>("app");
   builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
   //註冊IMovieRepository
   builder.Services.AddSingleton<IMovieRepository, MovieRepository>();
   await builder.Build().RunAsync();
 }
接下來我們在component中,注入我們剛剛的IMovieRepository。
@page "/movie"
@inject IMovieRepository movieRepository
<div class="container">
    <div class="row">
        <div class="col-8">
            <table class="table table-hover h5">
                <tr class="font-weight-bold">
                    <th>編號</th>
                    <th>電影名稱</th>
                    <th>放映日</th>
                </tr>
                @foreach (var item in movies)
                {
                    <tr>
                        <td>@item.Id</td>
                        <td>@item.Name</td>
                        <td>@item.ReleaseDate.ToShortDateString()</td>
                    </tr>
                }
            </table>
        </div>
    </div>
</div>
@code {
    private List<MovieDTO> movies;
    protected override void OnInitialized()
    {
        base.OnInitialized();
        movies = movieRepository.AllMovie();
    }
}